/*
    socklibpp library
    Copyright (C) 2005  Daniel K. O. <danielosmari at users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/



/**     \file sockstream.h
        \brief High-level stream classes for connection-oriented sockets.

*/


#ifndef SOCKSTREAM_H
#define SOCKSTREAM_H


#include "sockbuf.h"

#include <iosfwd>


namespace socklib {

/* TODO (DanielKO#1#): Add exceptions to these high-level classes */


/**     \brief  Input/Output stream class

        This is a convenience class; it doesn't provide detailed control over
        the connection.

        You shouldn't use this with non-blocking sockets, as there's no way to
        recover from a failed send/receive; this means that every operation on
        it may block, so you will either use it in a non-interactive program, or
        in a separated thread.
        
        Here's an example that uses a sockstream object to send a HTTP request
        and send it to cout.
        \include httpdump.cpp
*/
template <typename _CharT, typename _Traits = std::char_traits<_CharT> >
class basic_sockstream : public std::basic_iostream<_CharT, _Traits>
{
public:
        // Types:
        typedef _CharT                                  char_type;
        typedef _Traits                                 traits_type;

        typedef typename traits_type::int_type          int_type;
        typedef typename traits_type::pos_type          pos_type;
        typedef typename traits_type::off_type          off_type;

private:
        // Non-standard Types:
        typedef basic_sockbuf<_CharT, _Traits>          __sockbuf_type;
        typedef std::basic_iostream<char_type, traits_type>  __iostream_type;
        
        __sockbuf_type  _M_sockbuf;

public:
        basic_sockstream():basic_iostream( ??? )
        {
                this->init(&_M_sockbuf);
        }


        explicit
        basic_sockstream(const base& sock_)
        : _M_sockbuf(sock_)
        {
                this->init(&_M_sockbuf);
        }

        /**     \brief Construct a stream object and connect it to address
                \a _sin using a TCP connection.

                \param sin_     The address to connect.
        */
        explicit
        basic_sockstream(const addr_in sin_)
        : _M_sockbuf(sin_)
        {
                this->init(&_M_sockbuf);
        }
        
        virtual ~basic_sockstream()
        { }

        /// Return true if the stream is connected.
        bool is_connected() const throw() { return _M_sockbuf.is_connected(); }
        
        /// Connect the stream to a given address, calling sockbuf::connect().
        bool
        connect(const addr_in& sin_)
        {
                return _M_sockbuf.connect(sin_);
        }
        
        /// Connect the stream to a given address, calling sockbuf::connect().
        bool
        connect(const std::string& addr_, uint16_t port_)
        {
                return _M_sockbuf.connect(addr_, port_);
        }
        
        /// Close the connection, calling sockbuf::close()
        bool
        close()
        {
                return _M_sockbuf.close();
        }
};



/**     The default sockstream type

        This is probably the only typedef that makes sense for
        basic_sockstream. Be careful if you use basic_sockstream with
        another parameter (ike wchar_t).
*/
typedef basic_sockstream<char> sockstream;




/**     \brief Manipulator for sending a CRLF

        Sends a Carriage Return and a Line Feed (0x0D, 0x0A) to the ostream,
        then flushes it.
*/
std::ostream& crlf(std::ostream& o_)
{
        o_.put(o_.widen('\x00d'));
        o_.put(o_.widen('\x00a'));
        o_.flush();
        return o_;
}


/**     \brief Manipulator for sending a LFCR

        Sends a Line Feed and a Carriage Return (0x0A, 0x0D) to the ostream,
        then flushes it.
*/
std::ostream& lfcr(std::ostream& o_)
{
        o_.put(o_.widen('\x00a'));
        o_.put(o_.widen('\x00d'));
        o_.flush();
        return o_;
}

} // namespace sock



#endif
